package languageObject.parseur;

import java.io.File;
import java.util.Iterator;

import languageObject.VisiteurObject;
import languageObject.metatModel.ElementObject;
import languageObject.metatModel.LiaisonElement;
import languageObject.metatModel.SousElementObject;
import languageObject.metatModel.enumeration.TypeElementObject;
import partager.TypeSousElement;
import partager.TypeSousElementVar;
import uspeedd.metamodel.enumeration.TypeAssociationUspeed;
import utils.FichierTexte;
import utils.StringUtils;
import constantes.ConstantesJava;

/**
 * permet de generer un metaModel en java.
 */
public class Java implements VisiteurObject
{
	private String racine;
	
	/**
	 * Constructeur par recopie.
	 */
	public Java(String racine)
	{
		this.racine = racine;
		
		if(this.racine != null)
		{
			File file = new File(this.racine);
			if(!file.exists()) file.mkdirs();
		}
	}
	
	@Override
	public boolean ecriture(ElementObject element) 
	{
		if(element == null || element.getNom() == null) return false;

		File file = new File(racine + element.getNom() + ".java");
		FichierTexte fich = new FichierTexte(file);
		StringBuffer buffer = new StringBuffer();
		
/***************************************************************************************************/
/*********************le package.*******************************************************************/
/***************************************************************************************************/
		fich.ecriture("package sortie.java;\n"); //TODO a modifier avec le lien donner.
				
/***************************************************************************************************/
/*********************le commentaire.***************************************************************/
/***************************************************************************************************/
		if(StringUtils.IsNotBank(element.getNote()))
		{
			buffer.append("/** ");
			buffer.append(element.getNote());
			buffer.append(" */");
			fich.ecriture(buffer.toString());
			buffer.replace(0, buffer.length(), "");
		}
		
/***************************************************************************************************/
/*********************nommage du type JAVA.*********************************************************/
/***************************************************************************************************/
		if(element.getType() == null || element.getNom() == null) return false;
		
		buffer.append(ConstantesJava.VISIBILITE_PUBLIC);
		buffer.append(element.getType().getnum());
		buffer.append(" ");
		buffer.append(element.getNom());
		buffer.append(" ");
		
		if(element.getLiaison() != null)
		{
			Iterator<LiaisonElement> itExtends = element.getLiaison().iterator();
			boolean first = true;
			while(itExtends.hasNext())
			{
				LiaisonElement extend = itExtends.next();
				if(TypeAssociationUspeed.EXTENDS.equals(extend.getType()))
				{
					if(first) buffer.append(ConstantesJava.EXTENDS);
					else  buffer.append(", ");
					
					if(extend.getElement() == null) return false;
					buffer.append(extend.getElement().getNom());
				}
			}
			
			itExtends = element.getLiaison().iterator();
			first = true;
			while(itExtends.hasNext())
			{
				LiaisonElement implement = itExtends.next();
				if(TypeAssociationUspeed.IMPLEMENT.equals(implement.getType()))
				{
					if(first) buffer.append(ConstantesJava.IMPLEMENTS);
					else  buffer.append(", ");
					
					if(implement.getElement() == null) return false;
					buffer.append(implement.getElement().getNom());
				}
			}
		}
		fich.ecriture(buffer.toString());
		buffer.replace(0, buffer.length(), "");
		fich.ecriture("{");

		if(!TypeElementObject.INTERFACE.equals(element.getType()))
		{
/***************************************************************************************************/
/*********************creations des variables.******************************************************/
/***************************************************************************************************/
			Iterator<SousElementObject> itVariable = element.getSousElement().iterator();
			while(itVariable.hasNext())
			{
				SousElementObject variable = itVariable.next();
				
				if(TypeSousElement.ATTRIBUT.equals(variable.getType()))
				{
					buffer.append("\t" + ConstantesJava.VISIBILITE_PRIVATE);
					buffer.append(listeOuPasListe(variable.getTypeOutput()));
					
					buffer.append(variable.getNom() + ";\n");
				}
			}
			fich.ecriture(buffer.toString());
			buffer.replace(0, buffer.length(), "");
			
/***************************************************************************************************/
/*********************creations du constructeur.****************************************************/
/***************************************************************************************************/
			fich.ecriture("\tpublic " + element.getNom() + "()\n\t{\n\t}\n");
		}
		
/***************************************************************************************************/
/*********************creations des methodes.*******************************************************/
/***************************************************************************************************/
		Iterator<SousElementObject>  itMethode = element.getSousElement().iterator();
		while(itMethode.hasNext())
		{
			boolean retour = false;
			
			SousElementObject methode = itMethode.next();
			
			if(TypeSousElement.METHODE.equals(methode.getType()))
			{
				buffer.append("\t" + ConstantesJava.VISIBILITE_PUBLIC);
				if(methode.getTypeOutput() != null)
				{
					buffer.append(listeOuPasListe(methode.getTypeOutput()));
					retour = true;
				}
				else
				{
					buffer.append("void ");
				}
				buffer.append(methode.getNom());
				buffer.append("(");
				if(methode.getTypeInput() != null)
				{
					Iterator<SousElementObject> it = methode.getTypeInput().iterator();
					while(it.hasNext())
					{
						SousElementObject sous = it.next();
						
						buffer.append(listeOuPasListe(sous.getTypeOutput()));

						buffer.append(sous.getNom());
						
						if(it.hasNext()) buffer.append(", ");
					}
				}	
				
				if(TypeElementObject.INTERFACE.equals(element.getType()))
				{
					buffer.append(");");
				}
				else
				{
					buffer.append(")\n");
					buffer.append("\t{\n");
					buffer.append("\t\t return");
					if(retour) buffer.append(" null;");
					else buffer.append(";");
					buffer.append("\n\t}\n");
				}
				if(itMethode.hasNext()) buffer.append("\n");
			}			
		}
		fich.ecriture(buffer.toString());
		buffer.replace(0, buffer.length(), "");
		
		if(!TypeElementObject.INTERFACE.equals(element.getType()))
		{
/***************************************************************************************************/
/*********************creations des getteur and setteur.********************************************/
/***************************************************************************************************/
			Iterator<SousElementObject> itVariable = element.getSousElement().iterator();
			while(itVariable.hasNext())
			{
				SousElementObject variable = itVariable.next();
				
				if(TypeSousElement.ATTRIBUT.equals(variable.getType()))
				{
					buffer.append("\tpublic ");
					buffer.append(listeOuPasListe(variable.getTypeOutput()));
					buffer.append(" get");
					buffer.append(StringUtils.NomFonction(variable.getNom()));
					buffer.append("() {");
					buffer.append("return this.");
					buffer.append(variable.getNom());
					buffer.append(";}\n");
					
					buffer.append("\tpublic void set");
					buffer.append(StringUtils.NomFonction(variable.getNom()));
					buffer.append("(");
					buffer.append(listeOuPasListe(variable.getTypeOutput()));
					buffer.append(variable.getNom());
					buffer.append(") {this.");
					buffer.append(variable.getNom());
					buffer.append(" = ");
					buffer.append(variable.getNom());
					buffer.append(";}");
					
					fich.ecriture(buffer.toString());
					buffer.replace(0, buffer.length(), "");
				}
			}
			
			
/***************************************************************************************************/
/*********************creations des methodes donner par les interfaces.*****************************/
/***************************************************************************************************/
			if(element.getLiaison() != null)
			{
				for(int i = 0; i < element.getLiaison().size(); ++i)
				{
					if(element.getLiaison().get(i).getElement() != null && TypeElementObject.INTERFACE.equals(element.getLiaison().get(i).getElement().getType()))
					{
						ElementObject interfac = element.getLiaison().get(i).getElement();
						
						if(interfac.getSousElement() != null)
						{
							Iterator<SousElementObject> itSous = interfac.getSousElement().iterator();
							
							while(itSous.hasNext())
							{
								SousElementObject methode = itSous.next();
								
								if(TypeSousElement.METHODE.equals(methode.getType()))
								{
									boolean retour = false;
									
									buffer.append("\n");
									buffer.append("\t@Override\n");
									buffer.append("\tpublic ");
									if(methode.getTypeOutput() != null)
									{
										buffer.append(listeOuPasListe(methode.getTypeOutput()));
										retour = true;
									}
									else
									{
										buffer.append("void ");
									}
									buffer.append(methode.getNom());
									buffer.append("(");
									if(methode.getTypeInput() != null)
									{
										Iterator<SousElementObject> it = methode.getTypeInput().iterator();
										while(it.hasNext())
										{
											SousElementObject sous = it.next();
											
											buffer.append(listeOuPasListe(sous.getTypeOutput()));
	
											buffer.append(sous.getNom());
											
											if(it.hasNext()) buffer.append(", ");
										}
									}
									buffer.append("){return ");
									if(retour) buffer.append("null;");
									else buffer.append(";");
									buffer.append("}");
								
									fich.ecriture(buffer.toString());
									buffer.replace(0, buffer.length(), "");
								}
							}
						}
					}
				}
			}
		}
	
		fich.ecriture("}\n");
		fich.close();
		
		return true;
	}

	/**
	 * permet de donner le type complet de l'attribut.
	 * @param var la variable.
	 * @return le string de la variable.
	 */
	private String listeOuPasListe(TypeSousElementVar var)
	{
		if(var == null) return new String();
		
		if(var.getList()) return new String("List<" + var.getNom() + "> ");
		else return new String(var.getNom() + " ");
	}
	
	
	
	@Override
	public void setRacine(String racine) 
	{
		if(this.racine != null)
		{
			File file = new File(this.racine);
			if(!file.exists()) file.mkdirs();
		}
	}
}
